package com.sl.biz.modular.process.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.google.common.collect.Maps;
import com.sl.auth.core.util.StpCompositeUtil;
import com.sl.biz.modular.process.controller.request.*;
import com.sl.biz.modular.process.controller.response.ProcessVersionVO;
import com.sl.biz.modular.process.dao.domain.entity.ProcessConfigDO;
import com.sl.biz.modular.process.dao.domain.entity.ProcessVersionContentDO;
import com.sl.biz.modular.process.dao.domain.entity.ProcessVersionDO;
import com.sl.biz.modular.process.dao.service.ProcessConfigDaoService;
import com.sl.biz.modular.process.dao.service.ProcessVersionContentDaoService;
import com.sl.biz.modular.process.dao.service.ProcessVersionDaoService;
import com.sl.biz.modular.process.helper.ProcessFrontFileToBackFileHelper;
import com.sl.biz.modular.process.service.ProcessVersionContentBizService;
import com.sl.core.domain.dto.SquareLakeLayout;
import com.sl.core.domain.dto.Transformation;
import com.sl.core.domain.dto.TransformationOrder;
import com.sl.core.domain.dto.TransformationStep;
import com.sl.core.engine.ProcessConfig;
import com.sl.core.engine.ProcessEngine;
import com.sl.core.engine.check.ProcessCompCheckResult;
import com.sl.core.engine.loader.ProcessSourceFileLoader;
import com.sl.core.engine.meta.row.ProcessRowDescriptor;
import com.sl.core.engine.scripts.GroovyCondition;
import com.sl.core.engine.scripts.GroovyRule;
import com.sl.core.engine.trans.ProcessInstancePool;
import com.sl.core.engine.utils.TidUtil;
import com.sl.core.utils.JsonUtil;
import com.sl.core.utils.KeyValueBuilder;
import com.sl.plugin.step.switchcase.SwitchCaseComp;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ProcessVersionContentBizServiceImpl implements ProcessVersionContentBizService, ProcessSourceFileLoader {

    private final ProcessVersionDaoService versionDaoService;

    private final ProcessConfigDaoService configDaoService;

    private final ProcessVersionContentDaoService processVersionContentDaoService;


    public ProcessVersionContentBizServiceImpl(ProcessVersionDaoService versionDaoService,
                                               ProcessConfigDaoService configDaoService,
                                               ProcessVersionContentDaoService processVersionContentDaoService) {
        this.versionDaoService = versionDaoService;
        this.configDaoService = configDaoService;
        this.processVersionContentDaoService = processVersionContentDaoService;
    }

    @Override
    public ProcessVersionVO getById(ProcessVersionDO addRequest) {

        ProcessVersionDO byId = versionDaoService.getById(addRequest.getId());

        if (ObjectUtil.isNull(byId)) {
            return null;
        }
        //还要获取xml
        ProcessVersionContentDO processVersionContentDO = processVersionContentDaoService.queryByProcessVersionId(byId.getId());
        if (ObjectUtil.isNull(processVersionContentDO)) {
            processVersionContentDO = new ProcessVersionContentDO();
        }
//        String content = processVersionContentDO.getContent();
//        SquareLakeLayout byIdAndVersion = JsonUtil.toBean(content, SquareLakeLayout.class);
//        if (ObjectUtil.isNull(byIdAndVersion)) {
//            byIdAndVersion = new SquareLakeLayout();
//        }
        ProcessVersionVO processVersionVO = BeanUtil.copyProperties(byId, ProcessVersionVO.class);
        String processId = processVersionVO.getProcessId();

//        ProcessResourceVO processResourceVO = JsonUtil.toBean(byIdAndVersion.getTransformation(), ProcessResourceVO.class);
        processVersionVO.setBackFile(processVersionContentDO.getBackFile());
        processVersionVO.setFrontFile(processVersionContentDO.getFrontFile());

        //还要获取名称编码
        ProcessConfigDO configDO = configDaoService.getById(processId);
        if (ObjectUtil.isNull(configDO)) {
            return processVersionVO;
        }
        processVersionVO.setProcessCode(configDO.getProcessCode());
        processVersionVO.setProcessName(configDO.getProcessName());
        return processVersionVO;
    }

    @Override
    public Boolean saveXml(SquareLakeProcessResourceAddRequest addRequest) {
        //要得到openId
//        ProcessVersionDO byId = versionDaoService.getById(addRequest.getId());
        ProcessVersionDO processVersionDO = new ProcessVersionDO();
        processVersionDO.setId(addRequest.getId());
        ProcessVersionVO byId = getById(processVersionDO);
        if (ObjectUtil.isNull(byId)) {
            return null;
        }
        Map<String, Object> frontFile = addRequest.getFrontFile();

        //前端流程文件转后端可执行文件
        SquareLakeLayout squareLakeLayout = ProcessFrontFileToBackFileHelper.INSTANCE.frontToBack(frontFile, byId.getProcessName());
        ProcessVersionContentDO processVersionContentDO = processVersionContentDaoService.queryByProcessVersionId(addRequest.getId());
        processVersionContentDO.setFrontFile(JsonUtil.toStr(addRequest.getFrontFile()));
        processVersionContentDO.setBackFile(JsonUtil.toStr(squareLakeLayout));
        processVersionContentDaoService.updateById(processVersionContentDO);
        String id = processVersionContentDO.getId();
        ProcessInstancePool.INSTANCE.clear(id);
        return Boolean.TRUE;
    }


    @Override
    public String tid() {
        return TidUtil.getTid();
    }

    @InterceptorIgnore(tenantLine = "true")
    @Override
    public Object run(SquareLakeProcessRunRequest runRequest) {

        ProcessConfig processConfig = getProcessConfig(runRequest.getId(), runRequest.getProcessId(), runRequest.getProcessVersion());
        processConfig.setTid(runRequest.getTid());
        Map<String,Object> map= Maps.newHashMap();
        String userId = runRequest.getUserId();
        if(StrUtil.isBlank(userId)){
            userId = StpCompositeUtil.getUserIdChosen();
        }
        map.put("userId",userId );

        Object execute = ProcessEngine.INSTANCE.execute(runRequest.getParam(), processConfig,null,false,null,map);
        return execute;
    }

    public ProcessConfig getProcessConfig(String processVersionId, String processId, String processVersion) {
        ProcessVersionDO byId = null;
        if (StrUtil.isBlank(processVersionId)) {
            byId = versionDaoService.queryByProcessIdAndVersion(processId, processVersion);
        } else {
            byId = versionDaoService.getById(processVersionId);
        }
        //要得到openId
        if (ObjectUtil.isNull(byId)) {
            return null;
        }
        ProcessConfigDO configDO = configDaoService.getById(byId.getProcessId());
        ProcessConfig processConfig = BeanUtil.copyProperties(configDO, ProcessConfig.class);
        processConfig.setProcessVersion(byId.getProcessVersion());
        processConfig.setProcessId(byId.getProcessId());

        ProcessVersionContentDO processVersionContentDO = processVersionContentDaoService.queryByProcessVersionId(byId.getId());

        if (ObjectUtil.isNull(processVersionContentDO)
                || StrUtil.isBlank(processVersionContentDO.getBackFile())) {
            Assert.isTrue(false, "获取流程信息失败");
        }
        //设置openId
        processConfig.setOpenId(processVersionContentDO.getId());
        String content = processVersionContentDO.getBackFile();

        SquareLakeLayout squareLakeLayout = JsonUtil.toBean(content, SquareLakeLayout.class);
        squareLakeLayout.getTransformation().rebuild();
        String s = squareLakeLayout.toXml();

        processConfig.setXml(s);
        processConfig.setRowSetTagDataSourceId(configDO.getRowSetTagDataSourceId());
        return processConfig;
    }

    @InterceptorIgnore(tenantLine = "true")
    @Override
    public ProcessConfig load(String groupId, String processVersionId, String processId, String processVersion) {
        ProcessConfig processConfig = getProcessConfig(processVersionId, processId, processVersion);
        return processConfig;

    }

    @Override
    public Boolean stepPause(SquareLakeProcessStepPauseRequest runRequest) {

        //要得到openId
        ProcessVersionDO byId = versionDaoService.getById(runRequest.getId());

        if (ObjectUtil.isNull(byId)) {
            return null;
        }
        ProcessConfigDO configDO = configDaoService.getById(byId.getProcessId());
        ProcessConfig processConfig = BeanUtil.copyProperties(configDO, ProcessConfig.class);
        processConfig.setProcessVersion(byId.getProcessVersion());
        processConfig.setProcessId(byId.getProcessId());
        Boolean execute = ProcessEngine.INSTANCE.stepPause(runRequest.getStepId(),
                runRequest.getTid(), processConfig);
        return execute;
    }

    @Override
    public Boolean stepResume(SquareLakeProcessStepPauseRequest runRequest) {
        //要得到openId
        ProcessVersionDO byId = versionDaoService.getById(runRequest.getId());

        if (ObjectUtil.isNull(byId)) {
            return null;
        }
        ProcessConfigDO configDO = configDaoService.getById(byId.getProcessId());
        ProcessConfig processConfig = BeanUtil.copyProperties(configDO, ProcessConfig.class);
        processConfig.setProcessVersion(byId.getProcessVersion());
        processConfig.setProcessId(byId.getProcessId());
        Boolean execute = ProcessEngine.INSTANCE.stepping(runRequest.getTid(), processConfig);
        return execute;
    }

    @Override
    public Boolean transResume(SquareLakeProcessStepPauseRequest runRequest) {
        //要得到openId
        ProcessVersionDO byId = versionDaoService.getById(runRequest.getId());

        if (ObjectUtil.isNull(byId)) {
            return null;
        }
        ProcessConfigDO configDO = configDaoService.getById(byId.getProcessId());
        ProcessConfig processConfig = BeanUtil.copyProperties(configDO, ProcessConfig.class);
        processConfig.setProcessVersion(byId.getProcessVersion());
        processConfig.setProcessId(byId.getProcessId());
        Boolean execute = ProcessEngine.INSTANCE.transResume(runRequest.getTid(), processConfig);
        return execute;
    }

    @Override
    public Boolean transResumeAll(SquareLakeProcessStepPauseRequest runRequest) {
        //要得到openId
        ProcessVersionDO byId = versionDaoService.getById(runRequest.getId());

        if (ObjectUtil.isNull(byId)) {
            return null;
        }
        ProcessConfigDO configDO = configDaoService.getById(byId.getProcessId());
        ProcessConfig processConfig = BeanUtil.copyProperties(configDO, ProcessConfig.class);
        processConfig.setProcessVersion(byId.getProcessVersion());
        processConfig.setProcessId(byId.getProcessId());
        Boolean execute = ProcessEngine.INSTANCE.transResumeAll(processConfig);
        return execute;
    }

    @Override
    public Object stepRun(SquareLakeProcessStepRunRequest runRequest) {
        //获取xml
        Map<String, Object> frontFile = runRequest.getFrontFile();
        SquareLakeLayout squareLakeLayout = ProcessFrontFileToBackFileHelper.INSTANCE.frontToBack(frontFile);

        String stepCode = runRequest.getStepCode();

        Transformation transformation = squareLakeLayout.getTransformation();
        TransformationOrder order = transformation.getOrder();
        order.getHop().clear();

        List<TransformationStep> step = transformation.getStep();
        List<TransformationStep> collect = step.stream().filter(v -> StrUtil.equals(v.getName(), stepCode)).collect(Collectors.toList());
        transformation.setStep(collect);

        //需要加一个对象输入组件
        transformation.addStep("JsonInput", "JsonInput", KeyValueBuilder.builder()
                .add("inputMeta", "").add("isArrayFlag", "false").build());

        transformation.addStep("JsonOutput", "JsonOutput", KeyValueBuilder.builder()
                .add("inputMeta", "").add("isArrayFlag", "false").build());
        //然后连线
        transformation.addHop("JsonInput", stepCode);
        transformation.addHop(stepCode, "JsonOutput");

        String s = squareLakeLayout.toXml();

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(s.getBytes(Charset.defaultCharset()));
        Object param = runRequest.getParam();

        Map<String, Object> maps = Maps.newHashMap();
        maps.put("tid", runRequest.getTid());
        maps.put("openId", runRequest.getId());
        ProcessEngine.INSTANCE.clearPool();
        Object execute = ProcessEngine.INSTANCE.execute(byteArrayInputStream, param, maps);
        ProcessEngine.INSTANCE.clearPool();
        return execute;
    }

    @Override
    public Map<String, Object> getCurrentInputDefine(SquareLakeProcessGetCurrentInputDefineRequest addRequest) {
        //获取xml
//        ProcessResourceSaveRequest resource = addRequest.getResource();
        Map<String, Object> frontFile = addRequest.getFrontFile();
        SquareLakeLayout squareLakeLayout = ProcessFrontFileToBackFileHelper.INSTANCE.frontToBack(frontFile);
        String stepCode = addRequest.getStepCode();

//        Transformation transformation = JsonUtil.toBean(resource, Transformation.class);
//        if (ObjectUtil.isNull(transformation)) {
//            return Maps.newHashMap();
//        }
//        transformation.rebuild();

//        SquareLakeLayout squareLakeLayout = new SquareLakeLayout();
//        squareLakeLayout.setTransformation(transformation);
        String s = squareLakeLayout.toXml();

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(s.getBytes(Charset.defaultCharset()));

        return ProcessEngine.INSTANCE.getCurrentInputDefine(byteArrayInputStream, stepCode);
    }

    @Override
    public Map<String, Object> getCurrentOutputDefine(SquareLakeProcessGetCurrentOutputDefineRequest addRequest) {
        //获取xml
        Map<String, Object> frontFile = addRequest.getFrontFile();

        SquareLakeLayout squareLakeLayout = ProcessFrontFileToBackFileHelper.INSTANCE.frontToBack(frontFile);
        String stepCode = addRequest.getStepCode();

        String s = squareLakeLayout.toXml();

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(s.getBytes(Charset.defaultCharset()));

        return ProcessEngine.INSTANCE.getCurrentOutputDefine(byteArrayInputStream, stepCode);
    }

    @Override
    public List<String> getNextTransforms(SquareLakeProcessGetNextTransformsRequest addRequest) {
        //获取xml

        String stepCode = addRequest.getStepCode();

        SquareLakeLayout squareLakeLayout = ProcessFrontFileToBackFileHelper.INSTANCE.frontToBack(addRequest.getFrontFile());
        String s = squareLakeLayout.toXml();

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(s.getBytes(Charset.defaultCharset()));

        return ProcessEngine.INSTANCE.getNextTransforms(byteArrayInputStream, stepCode);

    }

    @Override
    public String buildScripts(SquareLakeProcessBuildScriptsRequest buildScriptsRequest) {
        List<GroovyRule> groovyRuleList = SwitchCaseComp.buildScripts(buildScriptsRequest.getConditionDataList(), null);
        String s = new GroovyCondition(groovyRuleList).buildViewScript(Maps.newHashMap(), null);
        return s;
    }

    @Override
    public List<ProcessCompCheckResult> check(ProcessResourceCheckRequest checkRequest) {
        //获取xml
        SquareLakeLayout squareLakeLayout = ProcessFrontFileToBackFileHelper.INSTANCE.frontToBack(checkRequest.getFrontFile());
        String s = squareLakeLayout.toXml();

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(s.getBytes(Charset.defaultCharset()));

        return ProcessEngine.INSTANCE.check(byteArrayInputStream);
    }

    @Override
    public List<Map<String, Object>> getCurrentInputDefineGroup(SquareLakeProcessGetCurrentInputDefineGroupRequest checkRequest) {
        //获取xml

        String stepCode = checkRequest.getStepCode();

        Map<String, Object> frontFile = checkRequest.getFrontFile();

        SquareLakeLayout squareLakeLayout = ProcessFrontFileToBackFileHelper.INSTANCE.frontToBack(frontFile);

        String s = squareLakeLayout.toXml();

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(s.getBytes(Charset.defaultCharset()));

        return ProcessEngine.INSTANCE.getCurrentInputDefineGroup(byteArrayInputStream, stepCode);

    }

    @Override
    public Map<String, Object> getProcessEventInputDefine(SquareLakeProcessGetProcessInputDefineRequest addRequest) {
        Map<String, Object> frontFile = addRequest.getFrontFile();
        SquareLakeLayout squareLakeLayout = ProcessFrontFileToBackFileHelper.INSTANCE.frontToBack(frontFile);

        String s = squareLakeLayout.toXml();

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(s.getBytes(Charset.defaultCharset()));

        return ProcessEngine.INSTANCE.getProcessEventInputDefine(byteArrayInputStream);
    }

    @Override
    public Map<String, Object> runWithResultToFieldDefine(SquareLakeProcessResultToFieldDefineRequest runRequest) {
        SquareLakeProcessStepRunRequest squareLakeProcessStepRunRequest = new SquareLakeProcessStepRunRequest();
        squareLakeProcessStepRunRequest.setId(runRequest.getId());
        squareLakeProcessStepRunRequest.setFrontFile(runRequest.getFrontFile());
        squareLakeProcessStepRunRequest.setParam(runRequest.getParam());
        squareLakeProcessStepRunRequest.setStepCode(runRequest.getStepCode());
        squareLakeProcessStepRunRequest.setTid(runRequest.getTid());
        Object o = this.stepRun(squareLakeProcessStepRunRequest);
        ProcessRowDescriptor processRowDescriptor = ProcessRowDescriptor.objectToRowMeta(o);
        Map<String, Object> fieldDefine = processRowDescriptor.toFieldDefine();
        return fieldDefine;
    }

    @Override
    public Object compensate(SquareLakeProcessComensateRequest runRequest) {
        ProcessConfig processConfig = getProcessConfig(runRequest.getId(), runRequest.getProcessId(), runRequest.getProcessVersion());
        if (ObjectUtil.isNull(processConfig)) {
            return null;
        }
        processConfig.setTid(runRequest.getTid());
        processConfig.setCompensateLogId(runRequest.getLogId());
        Object execute = ProcessEngine.INSTANCE.compensate(processConfig);
        return execute;
    }

    @Override
    public Boolean save(ProcessVersionContentDO processVersionContentDO) {
       return processVersionContentDaoService.save(processVersionContentDO);
    }


}
